package com.breeze.components.core;

import cn.hutool.core.net.NetUtil;
import java.util.Optional;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

/**
 * @author breeze
 */
@Component("componentCoreServiceInfo")
public class ServiceInfo {

  private static final Logger logger = LoggerFactory.getLogger(ServiceInfo.class);

  private static final String PROPERTY_APP_ID = "spring.application.name";
  private static final String PROPERTY_APP_GROUP = "app.group";
  private static final String PROPERTY_APP_VERSION = "app.version";
  private static final String PROPERTY_PORT = "server.port";
  private static final String PROPERTY_ACTUATOR_PORT = "management.server.port";
  private static final String PROPERTY_HOST = "server.address";

  private static final String DEFAULT_APP_ID = "unknown";
  private static final String DEFAULT_APP_GROUP = "default";
  private static final String DEFAULT_APP_VERSION = "-1";
  private static final String DEFAULT_PORT = "8080";
  private static final String DEFAULT_HOST = "unknown";
  private static final String UNKNOWN_PORT = "unknown-port";
  private static final String UNKNOWN_HOST = "unknown-host";

  /** 应用名 */
  private static String appId;

  private static String appIdLowCase;

  /** 应用ip */
  private static String host;

  /** 应用端口 */
  private static String port;

  /** 探针端点端口 */
  private static String actuatorPort;

  /** 应用版本 */
  @Getter private static String version;

  /** 服务分组 */
  @Getter private static String group;

  public ServiceInfo(Environment env) {
    // appId
    ServiceInfo.appId = env.getProperty(PROPERTY_APP_ID);
    if (ServiceInfo.appId == null) {
      ServiceInfo.appId = DEFAULT_APP_ID;
      logger.info(
          "Could not match [%appId] because [{}] config not found! use default: [{}]",
          PROPERTY_APP_ID, DEFAULT_APP_ID);
    }
    ServiceInfo.appIdLowCase = ServiceInfo.appId.toLowerCase();
    // version
    ServiceInfo.version = env.getProperty(PROPERTY_APP_VERSION);
    if (ServiceInfo.version == null) {
      ServiceInfo.version = DEFAULT_APP_VERSION;
      logger.debug(
          "[{}] config not set, use default: [{}]", PROPERTY_APP_VERSION, DEFAULT_APP_VERSION);
    }
    // group
    ServiceInfo.group = env.getProperty(PROPERTY_APP_GROUP);
    if (ServiceInfo.group == null) {
      ServiceInfo.group = DEFAULT_APP_GROUP;
      logger.debug("[{}] config not set, use default [{}]", PROPERTY_APP_GROUP, DEFAULT_APP_GROUP);
    }
    // host
    ServiceInfo.host = env.getProperty(PROPERTY_HOST);
    if (ServiceInfo.host == null) {
      ServiceInfo.host = NetUtil.getLocalhostStr();
      logger.debug("[{}] config not set, use localhost [{}]", PROPERTY_HOST, ServiceInfo.host);
    }
    // port
    ServiceInfo.port = env.getProperty(PROPERTY_PORT);
    if (ServiceInfo.port == null) {
      ServiceInfo.port = DEFAULT_PORT;
      logger.debug("[{}] config not set, use default [{}]", PROPERTY_PORT, DEFAULT_PORT);
    }
    // actuatorPort
    ServiceInfo.actuatorPort = env.getProperty(PROPERTY_ACTUATOR_PORT);
    if (ServiceInfo.actuatorPort == null) {
      ServiceInfo.actuatorPort = DEFAULT_PORT;
      logger.debug("[{}] config not set, use default [{}]", PROPERTY_ACTUATOR_PORT, DEFAULT_PORT);
    }
  }

  public static String address() {
    return host + ":" + port;
  }

  public static String getAppId() {
    if (appId == null) {
      return System.getenv("PAAS_APP_NAME");
    } else {
      return appId;
    }
  }

  public static String getAppIdLowCase() {
    if (appIdLowCase == null) {
      appIdLowCase = System.getenv("PAAS_APP_NAME");
      if (appIdLowCase != null) {
        appIdLowCase = appIdLowCase.toLowerCase();
      }
    }
    return appIdLowCase;
  }

  public static String getHost() {
    return Optional.ofNullable(host).orElse(UNKNOWN_HOST);
  }

  public static String getPort() {
    return Optional.ofNullable(port).orElse(UNKNOWN_PORT);
  }

  public static String getActuatorPort() {
    return Optional.ofNullable(actuatorPort).orElse(UNKNOWN_PORT);
  }
}
